home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
QRZ! Ham Radio 6
/
QRZ Ham Radio Callsign Database - Volume 6.iso
/
mac
/
files
/
amiga
/
csrc720j.lzh
/
lzhuf.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-04-22
|
13KB
|
576 lines
/**************************************************************
lzhuf.c
written by Haruyasu Yoshizaki 11/20/1988
some minor changes 4/6/1989
comments translated by Haruhiko Okumura 4/7/1989
Taken from the FBB distribution and modified to do an in-memory
(de)compression.
**************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
unsigned long int textsize = 0, codesize = 0;
FILE *infl;
extern short huf_error;
extern unsigned char gethuf();
extern char tmpstr[];
char wterr[] = "Can't write.";
/********** LZSS compression **********/
/* Confirmed by F6FBB that N should be 2048 */
#define N 2048 /*4096*/ /* buffer size */
#define F 60 /* lookahead buffer size */
#define THRESHOLD 2
#define NIL N /* leaf of tree */
#ifndef MCH_AMIGA
unsigned char
text_buf[N + F - 1];
int match_position, match_length,
*lson, rson[N + 257], dad[N + 1];
#else
extern short block_cancel;
unsigned char *text_buf;
int match_position, match_length,
*lson, *rson, *dad;
#endif
void InitTree(void) /* initialize trees */
{
int i;
for (i = N + 1; i <= N + 256; i++)
rson[i] = NIL; /* root */
for (i = 0; i < N; i++)
dad[i] = NIL; /* node */
}
void InsertNode(int r) /* insert to tree */
{
int i, p, cmp;
unsigned char *key;
unsigned c;
cmp = 1;
key = &text_buf[r];
p = N + 1 + key[0];
rson[r] = lson[r] = NIL;
match_length = 0;
for ( ; ; ) {
if (cmp >= 0) {
if (rson[p] != NIL)
p = rson[p];
else {
rson[p] = r;
dad[r] = p;
return;
}
} else {
if (lson[p] != NIL)
p = lson[p];
else {
lson[p] = r;
dad[r] = p;
return;
}
}
for (i = 1; i < F; i++)
if ((cmp = key[i] - text_buf[p + i]) != 0)
break;
if (i > THRESHOLD) {
if (i > match_length) {
match_position = ((r - p) & (N - 1)) - 1;
if ((match_length = i) >= F)
break;
}
if (i == match_length) {
if ((c = ((r - p) & (N - 1)) - 1) < match_position) {
match_position = c;
}
}
}
}
dad[r] = dad[p];
lson[r] = lson[p];
rson[r] = rson[p];
dad[lson[p]] = r;
dad[rson[p]] = r;
if (rson[dad[p]] == p)
rson[dad[p]] = r;
else
lson[dad[p]] = r;
dad[p] = NIL; /* remove p */
}
void DeleteNode(int p) /* remove from tree */
{
int q;
if (dad[p] == NIL)
return; /* not registered */
if (rson[p] == NIL)
q = lson[p];
else
if (lson[p] == NIL)
q = rson[p];
else {
q = lson[p];
if (rson[q] != NIL) {
do {
q = rson[q];
} while (rson[q] != NIL);
rson[dad[q]] = lson[q];
dad[lson[q]] = dad[q];
lson[q] = lson[p];
dad[lson[p]] = q;
}
rson[q] = rson[p];
dad[rson[p]] = q;
}
dad[q] = dad[p];
if (rson[dad[p]] == p)
rson[dad[p]] = q;
else
lson[dad[p]] = q;
dad[p] = NIL;
}
/* Huffman coding */
#define N_CHAR (256 - THRESHOLD + F)
/* kinds of characters (character code = 0..N_CHAR-1) */
#define T (N_CHAR * 2 - 1) /* size of table */
#define R (T - 1) /* position of root */
#define MAX_FREQ 0x8000 /* updates tree when the */
/* root frequency comes to this value. */
typedef unsigned char uchar;
/* table for encoding and decoding the upper 6 bits of position */
/* I've moved these tables into another file so I don't have to print them
out all the time
*/
/* for encoding */
extern uchar p_len[];
extern uchar p_code[];
/* for decoding */
extern uchar d_code[];
extern uchar d_len[];
unsigned freq[T + 1]; /* frequency table */
int prnt[T + N_CHAR]; /* pointers to parent nodes, except for the */
/* elements [T..T + N_CHAR - 1] which are used to get */
/* the positions of leaves corresponding to the codes. */
int son[T]; /* pointers to child nodes (son[], son[] + 1) */
unsigned getbuf = 0;
uchar getlen = 0;
int GetBit(void) /* get one bit */
{
int i;
while (getlen <= 8) {
i = gethuf();
getbuf |= i << (8 - getlen);
getlen += 8;
}
i = getbuf;
getbuf <<= 1;
getlen--;
return (i < 0);
}
int GetByte(void) /* get one byte */
{
unsigned i;
while (getlen <= 8) {
i = gethuf();
getbuf |= i << (8 - getlen);
getlen += 8;
}
i = getbuf;
getbuf <<= 8;
getlen -= 8;
return i >> 8;
}
unsigned putbuf = 0;
uchar putlen = 0;
void Putcode(int l, unsigned c) /* output c bits of code */
{
putbuf |= c >> putlen;
if ((putlen += l) >= 8) {
puthuf(putbuf >> 8);
if ((putlen -= 8) >= 8) {
puthuf(putbuf);
codesize += 2;
putlen -= 8;
putbuf = c << (l - putlen);
} else {
putbuf <<= 8;
codesize++;
}
}
}
/* initialization of tree */
void StartHuff(void)
{
int i, j;
for (i = 0; i < N_CHAR; i++) {
freq[i] = 1;
son[i] = i + T;
prnt[i + T] = i;
}
i = 0; j = N_CHAR;
while (j <= R) {
freq[j] = freq[i] + freq[i + 1];
son[j] = i;
prnt[i] = prnt[i + 1] = j;
i += 2; j++;
}
freq[T] = 0xffff;
prnt[R] = 0;
}
/* reconstruction of tree */
void reconst(void)
{
int i, j, k;
unsigned f, l;
/* collect leaf nodes in the first half of the table */
/* and replace the freq by (freq + 1) / 2. */
j = 0;
for (i = 0; i < T; i++) {
if (son[i] >= T) {
freq[j] = (freq[i] + 1) / 2;
son[j] = son[i];
j++;
}
}
/* begin constructing tree by connecting sons */
for (i = 0, j = N_CHAR; j < T; i += 2, j++) {
k = i + 1;
f = freq[j] = freq[i] + freq[k];
for (k = j - 1; f < freq[k]; k--);
k++;
l = (j - k) * 2;
memmove(&freq[k + 1], &freq[k], l);
freq[k] = f;
memmove(&son[k + 1], &son[k], l);
son[k] = i;
}
/* connect prnt */
for (i = 0; i < T; i++) {
if ((k = son[i]) >= T) {
prnt[k] = i;
} else {
prnt[k] = prnt[k + 1] = i;
}
}
}
/* increment frequency of given code by one, and update tree */
void update(int c)
{
int i, j, k, l;
if (freq[R] == MAX_FREQ) {
reconst();
}
c = prnt[c + T];
do {
k = ++freq[c];
/* if the order is disturbed, exchange nodes */
if (k > freq[l = c + 1]) {
while (k > freq[++l]);
l--;
freq[c] = freq[l];
freq[l] = k;
i = son[c];
prnt[i] = l;
if (i < T) prnt[i + 1] = l;
j = son[l];
son[l] = i;
prnt[j] = c;
if (j < T) prnt[j + 1] = c;
son[c] = j;
c = l;
}
} while ((c = prnt[c]) != 0); /* repeat up to root */
}
unsigned code, len;
EncodeChar(unsigned c)
{
unsigned i;
int j, k;
i = 0;
j = 0;
k = prnt[c + T];
/* travel from leaf to root */
do {
i >>= 1;
/* if node's address is odd-numbered, choose bigger brother node */
if (k & 1) i += 0x8000;
j++;
} while ((k = prnt[k]) != R);
Putcode(j, i);
code = i;
len = j;
update(c);
}
void EncodePosition(unsigned c)
{
unsigned i;
/* output upper 6 bits by table lookup */
i = c >> 6;
Putcode(p_len[i], (unsigned)p_code[i] << 8);
/* output lower 6 bits verbatim */
Putcode(6, (c & 0x3f) << 10);
}
void EncodeEnd(void)
{
if (putlen) {
puthuf(putbuf >> 8);
codesize++;
}
}
int DecodeChar(void)
{
unsigned c;
c = son[R];
/* travel from root to leaf, */
/* choosing the smaller child node (son[]) if the read bit is 0, */
/* the bigger (son[]+1} if 1 */
while (c < T) {
c += GetBit();
c = son[c];
}
c -= T;
update(c);
return c;
}
int DecodePosition(void)
{
unsigned i, j, c;
/* recover upper 6 bits from table */
i = GetByte();
c = (unsigned)d_code[i] << 6;
j = d_len[i];
/* read lower 6 bits verbatim */
j -= 2;
while (j--) {
i = (i << 1) + GetBit();
}
return c | (i & 0x3f);
}
/* compression */
Encode(void) /* compression */
{
int i, c, len, r, s, last_match_length;
/* Unfortunately, I don't know the true size of the file until I read the
whole thing because I have to map LF into CR/LF. So the message is
first written into the file t:fbb.tmp and then the file descriptor
infl is left open for Encode to deal with the file.
The calling routine has already written out the SOH header and
initialized the puthuf routine.
*/
putbuf = 0;
putlen = 0;
codesize = 0;
fseek(infl, 0L, SEEK_END);
textsize = ftell(infl);
/* Have to write the long out in IBM order ... low byte first */
puthuf((unsigned char)(textsize&0xff));
puthuf((unsigned char)((textsize >> 8) & 0xff));
puthuf((unsigned char)((textsize >> 16) & 0xff));
puthuf((unsigned char)((textsize >> 24) & 0xff));
rewind(infl);
textsize = 0; /* rewind and re-read */
StartHuff();
InitTree();
s = 0;
r = N - F;
for (i = s; i < r; i++)
text_buf[i] = ' ';
for (len = 0; len < F && (c = getc(infl)) != EOF; len++) {
text_buf[r + len] = c;
}
textsize = len;
for (i = 1; i <= F; i++)
InsertNode(r - i);
InsertNode(r);
do {
if (match_length > len)
match_length = len;
if (match_length <= THRESHOLD) {
match_length = 1;
EncodeChar(text_buf[r]);
} else {
EncodeChar(255 - THRESHOLD + match_length);
EncodePosition(match_position);
}
last_match_length = match_length;
for (i = 0; i < last_match_length &&
(c = getc(infl)) != EOF; i++) {
DeleteNode(s);
text_buf[s] = c;
if (s < F - 1)
text_buf[s + N] = c;
s = (s + 1) & (N - 1);
r = (r + 1) & (N - 1);
InsertNode(r);
}
while (i++ < last_match_length) {
DeleteNode(s);
s = (s + 1) & (N - 1);
r = (r + 1) & (N - 1);
if (--len) InsertNode(r);
}
#ifndef MCH_AMIGA
} while (len > 0);
#else
} while ((len > 0) && !block_cancel);
if(block_cancel)return(1);
#endif
EncodeEnd();
closehuf();
return(block_cancel);
}
Decode(void) /* recover */
{
register int i, j, k;
int r, c;
register unsigned long lzcount;
getbuf = 0;
getlen = 0;
codesize = 0;
/* get textsize from the first block of data
*/
textsize = (gethuf() & 0xff);
textsize |= ((gethuf() & 0xff) << 8) & 0xff00;
textsize |= ((gethuf() & 0xff) << 16) & 0xff0000L;
textsize |= ((gethuf() & 0xff) << 24) & 0xff000000L;
StartHuff();
for (i = 0; i < N - F; i++)
text_buf[i] = ' ';
r = N - F;
#ifndef MCH_AMIGA
for (lzcount = 0; lzcount < textsize; ) {
#else
for (lzcount = 0;(lzcount < textsize) && !block_cancel; ) {
#endif
c = DecodeChar();
if(huf_error)break;
if (c < 256) {
putdec(c);
text_buf[r++] = c;
r &= (N - 1);
lzcount++;
} else {
i = (r - DecodePosition() - 1) & (N - 1);
if(huf_error)break;
j = c - 255 + THRESHOLD;
for (k = 0; k < j; k++) {
c = text_buf[(i + k) & (N - 1)];
putdec(c);
if(block_cancel)break;
text_buf[r++] = c;
r &= (N - 1);
lzcount++;
}
}
}
if(huf_error || block_cancel)return(1);
closedec();
return(block_cancel);
}
extern char *out_buf_adr,*yapp_buf;
fbb_alloc()
{
if((out_buf_adr = AllocMem(260,MEMF_PUBLIC|MEMF_CHIP)) == NULL) {
fbb_free();
return(1);
}
if((yapp_buf = AllocMem(260,MEMF_PUBLIC|MEMF_CHIP)) == NULL) {
fbb_free();
return(1);
}
if((text_buf = AllocMem(N+F-1,MEMF_PUBLIC|MEMF_CHIP)) == NULL) {
fbb_free();
return(1);
}
if((lson = AllocMem((N+1)*sizeof(int),MEMF_PUBLIC|MEMF_CHIP)) == NULL) {
fbb_free();
return(1);
}
if((rson = AllocMem((N+257)*sizeof(int),MEMF_PUBLIC|MEMF_CHIP)) == NULL) {
fbb_free();
return(1);
}
if((dad = AllocMem((N+1)*sizeof(int),MEMF_PUBLIC|MEMF_CHIP)) == NULL) {
fbb_free();
return(1);
}
return(0);
}
fbb_free()
{
if(out_buf_adr)FreeMem(out_buf_adr,260);
out_buf_adr = 0;
if(yapp_buf)FreeMem(yapp_buf,260);
yapp_buf = 0;
if(text_buf)FreeMem(text_buf,N+F-1);
text_buf = 0;
if(lson)FreeMem(lson,(N+1)*sizeof(int));
lson = 0;
if(rson)FreeMem(rson,(N+257)*sizeof(int));
rson = 0;
if(dad)FreeMem(dad,(N+1)*sizeof(int));
dad = 0;
}